﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.DynamicProxy;
using System.Reflection;
using System.Linq.Expressions;
using Castle.Core.Interceptor;

namespace ReAnimation.Helpers.DynamicProxy
{
    public delegate void Action();

    [Serializable]
    public class EventsSourceInterceptor: IInterceptor
    {
        [NonSerialized]
        private IDictionary<MethodInfo, IList<Action>> _beforeCallSubscribers;
        [NonSerialized]
        private IDictionary<MethodInfo, IList<Action>> _afterCallSubscribers;

        public EventsSourceInterceptor()
        {
            _beforeCallSubscribers = new Dictionary<MethodInfo, IList<Action>>();
            _afterCallSubscribers = new Dictionary<MethodInfo, IList<Action>>();
        }

        #region IInterceptor Members

        public void Intercept(IInvocation invocation)
        {
            if(_beforeCallSubscribers == null)
                _beforeCallSubscribers = new Dictionary<MethodInfo, IList<Action>>();
            if(_afterCallSubscribers == null)
                _afterCallSubscribers = new Dictionary<MethodInfo, IList<Action>>();

            if (_beforeCallSubscribers.Keys.Contains(invocation.Method))
                foreach (Action handler in _beforeCallSubscribers[invocation.Method])
                    handler();

            invocation.Proceed();


            foreach (MethodInfo m in _afterCallSubscribers.Keys)
            {
                if (m.Name.Equals(invocation.Method.Name))
                {
                    foreach (Action handler in _afterCallSubscribers[m])
                        handler();
                }
            }
      
        }

        #endregion
        //TODO: eliminate copy&paste ?
        public void AddAfterMethodCallHandler(IList<MethodInfo> methods, Action handler)
        {
            foreach (MethodInfo method in methods)
            {
                if (!_afterCallSubscribers.ContainsKey(method))
                    _afterCallSubscribers.Add(method, new List<Action>());

                IList<Action> handlers = _afterCallSubscribers[method];
                handlers.Add(handler);
            }
        }

        public void AddBeforeMethodCallHandler(IList<MethodInfo> methods, Action handler)
        {
            foreach (MethodInfo method in methods)
            {
                if (!_beforeCallSubscribers.ContainsKey(method))
                    _beforeCallSubscribers.Add(method, new List<Action>());

                IList<Action> handlers = _beforeCallSubscribers[method];
                handlers.Add(handler);
            }
        }

        public void RemoveHandler(Action handler)
        {
            foreach (var handlersList in _afterCallSubscribers.Values)
                handlersList.Remove(handler);
            foreach (var handlersList in _beforeCallSubscribers.Values)
                handlersList.Remove(handler);
        }

        public void ClearSubscriptions()
        {
            _afterCallSubscribers.Clear();
            _beforeCallSubscribers.Clear();
        }
    }
}
